home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 18 / CU Amiga Magazine's Super CD-ROM 18 (1997)(EMAP Images)(GB)[!][issue 1998-01].iso / CUCD / Online / hsc / source / hsclib / eval.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-11-02  |  43.7 KB  |  1,778 lines

  1. /*
  2.  * This source code is part of hsc, a html-preprocessor,
  3.  * Copyright (C) 1995-1997  Thomas Aglassinger
  4.  *
  5.  * This program is free software; you can redistribute it and/or modify
  6.  * it under the terms of the GNU General Public License as published by
  7.  * the Free Software Foundation; either version 2 of the License, or
  8.  * (at your option) any later version.
  9.  *
  10.  * This program is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program; if not, write to the Free Software
  17.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  *
  19.  */
  20. /*
  21.  * hsclib/eval.c
  22.  *
  23.  * attribute value evaluation functions
  24.  *
  25.  * updated: 19-Oct-1997
  26.  * created: 11-Oct-1995
  27.  */
  28.  
  29. #define NOEXTERN_HSCLIB_EVAL_H
  30.  
  31. #include <ctype.h>
  32. #include <time.h>
  33.  
  34. #include "hsclib/inc_base.h"
  35.  
  36. #include "hsclib/eval.h"
  37. #include "hsclib/input.h"
  38. #include "hsclib/skip.h"
  39. #include "hsclib/uri.h"
  40.  
  41. /* maximul length of an operator identifer */
  42. #define MAX_OP_LEN 8
  43.  
  44. /* unknown operator */
  45. #define OP_NONE 0
  46.  
  47. /* step-size for temp. string */
  48. #define TMP_STEPSIZE 128
  49.  
  50. /*
  51.  * equation operators
  52.  */
  53. #define OP_EQ_STR  "="
  54. #define OP_NEQ_STR "<>"
  55. #define OP_GT_STR  ">"
  56. #define OP_LT_STR  "<"
  57. #define OP_GTE_STR ">="
  58. #define OP_LTE_STR "<="
  59. #define OP_CEQ_STR "=="         /* TODO: case sensitive string comparison */
  60. #define OP_INSIDE_STR "IN"
  61. #define OP_CL_BRAKET_STR ")"    /* closing braket */
  62.  
  63. #define OP_EQ   1
  64. #define OP_NEQ  2
  65. #define OP_GT   3
  66. #define OP_LT   4
  67. #define OP_GTE  5
  68. #define OP_LTE  6
  69. #define OP_CEQ  7
  70. #define OP_INSIDE 8
  71. #define OP_CL_BRAKET  10
  72.  
  73. /*
  74.  * boolean operators
  75.  */
  76. #define OP_AND_STR "AND"
  77. #define OP_NOT_STR "NOT"
  78. #define OP_OR_STR  "OR"
  79. #define OP_XOR_STR "XOR"
  80.  
  81. #define OP_AND 11
  82. #define OP_NOT 12
  83. #define OP_OR  13
  84. #define OP_XOR 14
  85.  
  86. /*
  87.  * string/arithmetik operators
  88.  */
  89. #define OP_CAT_STR "+"
  90. #define OP_SUB_STR "-"
  91. #define OP_MUL_STR "*"
  92. #define OP_DIV_STR "/"
  93. #define OP_MOD_STR "MOD"        /* modulo */
  94.  
  95. #define OP_CAT      15
  96. #define OP_SUB      16
  97. #define OP_MUL      17
  98. #define OP_DIV      18
  99. #define OP_MOD      19
  100.  
  101. typedef BYTE op_t;
  102.  
  103. /*
  104.  * forward references
  105.  */
  106. STRPTR eval_expression(HSCPRC * hp, HSCATTR * dest, STRPTR endstr);
  107.  
  108. /*
  109.  * 
  110.  * global funcs
  111.  *
  112.  */
  113.  
  114. /*
  115.  * err_op: unknown binary operator
  116.  */
  117. static VOID err_op(HSCPRC * hp, STRPTR opstr)
  118. {
  119.     hsc_message(hp, MSG_UNKN_BINOP, "unknown binary operator %q", opstr);
  120. }
  121.  
  122. /*
  123.  * eval_boolstr
  124.  */
  125. static BOOL eval_boolstr(STRPTR s)
  126. {
  127.     if (s[0])
  128.         return (TRUE);
  129.     else
  130.         return (FALSE);
  131. }
  132.  
  133. /* check for empty brakets (after GetTime/GetGmTime) */
  134. static VOID check_brakets(HSCPRC * hp)
  135. {
  136.     if (parse_wd(hp, "("))
  137.         parse_wd(hp, ")");
  138. }
  139.  
  140. /*
  141.  * gettimestr
  142.  */
  143. static EXPSTR *gettimestr(HSCPRC * hp, struct tm *time)
  144. {
  145. #define TIMEBUF_INC 20
  146.     STRPTR timefmt = get_vartext_byname(hp->defattr, TIMEFORMAT_ATTR);
  147.     EXPSTR *timebuf = init_estr(TIMEBUF_INC);
  148.     BOOL strftrc = 0;           /* result of strftime() */
  149.     size_t i;                   /* loop var */
  150.  
  151.     /* set default time format */
  152.     if (!timefmt)
  153.     {
  154.         timefmt = "%d-%b-%Y, %H:%M";
  155.     }
  156.  
  157.     while (!(hp->fatal) && !strftrc)
  158.     {
  159.         /* expand timebuffer */
  160.         for (i = 0; i < TIMEBUF_INC; i++)
  161.             app_estrch(timebuf, '.');
  162.  
  163.         D(fprintf(stderr, DHL "    timebuf: inc+%d\n", TIMEBUF_INC));
  164.  
  165.         /* output time */
  166.         strftrc = strftime(estr2str(timebuf), estrlen(timebuf),
  167.                            timefmt, time);
  168.     }
  169.  
  170.     if (!strftrc)
  171.     {
  172.         del_estr(timebuf);
  173.         timebuf = NULL;
  174.     }
  175.  
  176.     return (timebuf);
  177. }
  178.  
  179. /*
  180.  * getfilesize
  181.  *
  182.  * get size of a specific file
  183.  *
  184.  * templates for HSC.FORMAT.FILESIZE:
  185.  * %b   size in byte
  186.  * %k   size in Kbyte
  187.  * %m   size in MByte
  188.  * %g   size in Gbyte
  189.  * %a   size, unit computed automatically
  190.  * %u   unit for %A (none, "K", "M" or "G")
  191.  */
  192. static STRPTR getfilesize(HSCPRC * hp, EXPSTR * dest, STRPTR uri)
  193. {
  194.     STRPTR filesizestr = NULL;
  195.     FILE *file = NULL;
  196.     LONG filesize = 0;          /* filesize in byte */
  197.     LONG filesize_k = 0;        /* filesize in Kbyte */
  198.     LONG filesize_m = 0;        /* filesize in Mbyte */
  199.     LONG filesize_g = 0;        /* filesize in Gbyte */
  200.     LONG filesize_auto = 0;     /* filesize in auto-units (%A) */
  201.     EXPSTR *efilename = init_estr(32);
  202.     STRPTR filename = NULL;
  203.     STRPTR sizeunit = "";
  204.     STRPTR s = get_vartext_byname(hp->defattr,
  205.                                   FILESIZEFORMAT_ATTR);
  206.  
  207.     conv_hscuri2file(hp, efilename, uri);
  208.     filename = estr2str(efilename);
  209.  
  210.     D(fprintf(stderr, DHL "  GETFILESIZE(`%s')\n", filename));
  211.     errno = 0;
  212.     file = fopen(filename, "rb");
  213.     if (file)
  214.     {
  215.         /* retrieve size */
  216.         fseek(file, 0L, SEEK_END);
  217.         filesize = ftell(file);
  218.         fclose(file);
  219.  
  220.         /* compute size in units, */
  221.         filesize_k = (filesize + 512) >> 10;
  222.         filesize_m = (filesize_k + 512) >> 10;
  223.         filesize_g = (filesize_m + 512) >> 10;
  224.  
  225.         /* compute auto-size */
  226.         if (filesize_g > 10)
  227.         {
  228.             filesize_auto = filesize_g;
  229.             sizeunit = "G";
  230.         }
  231.         else if (filesize_m > 10)
  232.         {
  233.             filesize_auto = filesize_m;
  234.             sizeunit = "M";
  235.         }
  236.         else if (filesize_k > 10)
  237.         {
  238.             filesize_auto = filesize_k;
  239.             sizeunit = "K";
  240.         }
  241.         else
  242.         {
  243.             filesize_auto = filesize;
  244.             sizeunit = "";
  245.         }
  246.     }
  247.     else
  248.     {
  249.         /* file not found */
  250.         filesize = 0;
  251.         filesize_k = 0;
  252.         filesize_m = 0;
  253.         filesize_g = 0;
  254.         filesize_auto = 0;
  255.         sizeunit = "";
  256.         hsc_msg_nouri(hp, filename, uri, "get filesize");
  257.     }
  258.  
  259.     /* parse template */
  260.     clr_estr(dest);
  261.     if (s)
  262.     {
  263.         while (s[0])
  264.         {
  265.             if (s[0] == '%')
  266.             {
  267.                 if (s[1])
  268.                     s++;
  269.                 switch (s[0])
  270.                 {
  271.                 case 'b':
  272.                     app_estr(dest, long2str(filesize));
  273.                     break;
  274.  
  275.                 case 'k':
  276.                     app_estr(dest, long2str(filesize_k));
  277.                     break;
  278.  
  279.                 case 'm':
  280.                     app_estr(dest, long2str(filesize_m));
  281.                     break;
  282.  
  283.                 case 'g':
  284.                     app_estr(dest, long2str(filesize_g));
  285.                     break;
  286.  
  287.                 case 'a':
  288.                     app_estr(dest, long2str(filesize_auto));
  289.                     break;
  290.  
  291.                 case 'u':
  292.                     app_estr(dest, sizeunit);
  293.                     break;
  294.  
  295.                 default:
  296.                     app_estrch(dest, '%');
  297.                     app_estrch(dest, s[0]);
  298.                     break;
  299.                 }
  300.             }
  301.             else
  302.                 app_estrch(dest, s[0]);
  303.             s++;
  304.         }
  305.     }
  306.     else
  307.     {
  308.         D(panic("no template for filesize-format"));
  309.     }
  310.  
  311.     /* set filesize-str */
  312.     filesizestr = estr2str(dest);
  313.     D(fprintf(stderr, DHL "  =`%s'\n", filesizestr));
  314.  
  315.     del_estr(efilename);
  316.  
  317.     return (filesizestr);
  318. }
  319.  
  320. /*
  321.  * check_attrname
  322.  *
  323.  * check string for legal attribute name
  324.  */
  325. BOOL check_attrname(HSCPRC * hp, STRPTR name)
  326. {
  327.     BOOL ok = FALSE;
  328.  
  329.     if (hsc_normch(name[0]))
  330.     {
  331.         ok = TRUE;
  332.     }
  333.     else
  334.     {
  335.         hsc_message(hp, MSG_ILLG_ATTRNAME,
  336.                     "illegal attribute identifier %q", name);
  337.     }
  338.  
  339.     return (ok);
  340. }
  341.  
  342. /*
  343.  * eval_attrname
  344.  *
  345.  * read next word and check it for a legal
  346.  * attribute identifier
  347.  */
  348. static STRPTR eval_attrname(HSCPRC * hp)
  349. {
  350.     STRPTR result = NULL;
  351.     STRPTR nw = infgetw(hp->inpf);
  352.  
  353.     if (nw)
  354.     {
  355.         if (check_attrname(hp, nw))
  356.         {
  357.             result = nw;
  358.         }
  359.     }
  360.     else
  361.     {
  362.         hsc_msg_eof(hp, "attribute identifier expected");
  363.     }
  364.  
  365.     return (result);
  366. }
  367.  
  368. /*
  369.  * quotestr
  370.  *
  371.  * return readable string for quote-kind
  372.  */
  373. STRPTR quotestr(int quote)
  374. {
  375.     STRPTR s = "UNKNOWN";
  376.  
  377.     if (quote == DOUBLE_QUOTE)
  378.     {
  379.         s = "[double]";
  380.     }
  381.     else if (quote == SINGLE_QUOTE)
  382.     {
  383.         s = "[single]";
  384.     }
  385.     else if (quote == BACK_QUOTE)
  386.     {
  387.         s = "[back]";
  388.     }
  389.     else if (quote == VQ_NO_QUOTE)
  390.     {
  391.         s = "[none]";
  392.     }
  393.     else
  394.     {
  395.         STRARR tmp[60];
  396.         sprintf(tmp, "unknown quote-kind: $%02x #%03d", quote, quote);
  397.         panic(tmp);
  398.     }
  399.  
  400.     return (s);
  401. }
  402.  
  403. /*
  404.  * choose_quote
  405.  *
  406.  * choose quote to be used for attr, depending on
  407.  * hp->quotemode and quotes used inside the value
  408.  */
  409. VOID choose_quote(HSCPRC * hp, HSCATTR * attr)
  410. {
  411.     int quote = attr->quote;
  412.     LONG qm = hp->quotemode;    /* lazy.. */
  413.     BOOL single_quote = FALSE;
  414.     BOOL double_quote = FALSE;
  415.     BOOL nasty_char = FALSE;
  416.  
  417.     STRPTR value = get_vartext(attr);
  418.  
  419.     D(fprintf(stderr, DHL "  choosing quote\n"));
  420.  
  421.     if (attr->vartype == VT_BOOL)
  422.     {
  423.         D(fprintf(stderr, DHL "    forget it, it's just a boolean attrib\n"));
  424.     }
  425.     else if (value[0])
  426.     {
  427.         /* scan attribute value for quotes */
  428.         while (value[0])
  429.         {
  430.             if (value[0] == SINGLE_QUOTE)
  431.             {
  432.                 D(fprintf(stderr, DHL "    single quote detected\n"));
  433.                 single_quote = TRUE;
  434.                 nasty_char = TRUE;
  435.             }
  436.             else if (value[0] == DOUBLE_QUOTE)
  437.             {
  438.                 D(fprintf(stderr, DHL "    double quote detected\n"));
  439.                 double_quote = TRUE;
  440.                 nasty_char = TRUE;
  441.             }
  442.             else if ((!hsc_normch(value[0]) || (value[0] == '_'))
  443.                      && !nasty_char)
  444.             {
  445.                 D(fprintf(stderr, DHL "    nasty-char #%d detected\n", value[0]));
  446.                 nasty_char = TRUE;
  447.             }
  448.  
  449.             value++;
  450.         }
  451.     }
  452.     else
  453.     {
  454.         /* empty value */
  455.         nasty_char = TRUE;
  456.         /* TODO: warninbg "empty value" */
  457.     }
  458.  
  459.     if (qm == QMODE_KEEP)
  460.     {
  461.         /* check, if quote is missing */
  462.         if ((attr->quote == VQ_NO_QUOTE)
  463.             && nasty_char)
  464.         {
  465.             hsc_message(hp, MSG_REQU_QUOTE,
  466.                         "value for %A requires quotes", attr);
  467.         }
  468.     }
  469.     else
  470.     {
  471.         /* choose quote */
  472.         if (single_quote && double_quote)
  473.         {
  474.             /* both kind of quotes appeared in value:
  475.              * replace double-quotes by """ */
  476.             EXPSTR *newval = init_estr(32);     /* new attribute value */
  477.  
  478.             /* scan old value for `\"', replace them by `"'
  479.              * and store new value in newval */
  480.             value = get_vartext(attr);
  481.             while (value[0])
  482.             {
  483.                 if (value[0] == DOUBLE_QUOTE)
  484.                 {
  485.                     D(fprintf(stderr, DHL "    replace by `"' in value\n"));
  486.                     /* TODO: message */
  487.                     app_estr(newval, """);
  488.                 }
  489.                 else
  490.                     app_estrch(newval, value[0]);
  491.                 value++;
  492.             }
  493.  
  494.             /* update attribute value */
  495.             set_vartext(attr, estr2str(newval));
  496.  
  497.             quote = DOUBLE_QUOTE;
  498.  
  499.             del_estr(newval);
  500.         }
  501.         else
  502.         {
  503.             if (single_quote)
  504.             {
  505.                 D(fprintf(stderr, DHL "    double quote forced\n"));
  506.                 quote = DOUBLE_QUOTE;
  507.             }
  508.             else if (double_quote)
  509.             {
  510.                 D(fprintf(stderr, DHL "    single quote forced\n"));
  511.                 quote = SINGLE_QUOTE;
  512.             }
  513.             else
  514.             {
  515.                 /* no quote in value: choose quote user prefers */
  516.                 if (qm == QMODE_SINGLE)
  517.                 {
  518.                     D(fprintf(stderr, DHL "    single quote preferd\n"));
  519.                     quote = SINGLE_QUOTE;
  520.                 }
  521.                 else if (qm == QMODE_DOUBLE)
  522.                 {
  523.                     D(fprintf(stderr, DHL "    double quote prefered\n"));
  524.                     quote = DOUBLE_QUOTE;
  525.                 }
  526.                 else if (qm == QMODE_NONE)
  527.                 {
  528.                     if (nasty_char)
  529.                     {
  530.                         D(fprintf(stderr, DHL "    quote needed (nasty char)\n"));
  531.                         quote = DOUBLE_QUOTE;
  532.                     }
  533.                     else
  534.                     {
  535.                         D(fprintf(stderr, DHL "    no quote needed\n"));
  536.                         quote = VQ_NO_QUOTE;
  537.                     }
  538.                 }
  539.                 else
  540.                 {
  541.                     panic("illegal quote-mode");
  542.                 }
  543.             }
  544.         }
  545.         /* check, if quote has changed */
  546.         if (attr->quote != quote)
  547.         {
  548.             hsc_message(hp, MSG_CHANGED_QUOTE,
  549.                         "changed quotes for %A from %s to %s",
  550.                         attr, quotestr(attr->quote), quotestr(quote));
  551.         }
  552.     }
  553.  
  554.     attr->quote = quote;
  555. }
  556.  
  557. /*
  558.  * try_eval_unary_op
  559.  *
  560.  * reads next word and tries to interpret it as an unary
  561.  * operator; if no fitting operator exists, return NULL,
  562.  * else immediatly process the operator and return its
  563.  * result
  564.  */
  565. static STRPTR try_eval_unary_op(HSCPRC * hp, HSCATTR * dest, BOOL * err)
  566. {
  567.     STRPTR eval_result = NULL;
  568.     INFILE *inpf = hp->inpf;
  569.     STRPTR nw = eval_attrname(hp);
  570.     HSCATTR *tmpdest = new_hscattr(PREFIX_TMPATTR "unary.operator");
  571.  
  572.     tmpdest->vartype = VT_STRING;
  573.  
  574.     *err = FALSE;
  575.     if (nw)
  576.     {
  577.         if (!upstrcmp(nw, "NOT"))
  578.         {
  579.             /* TODO: this part looks a bit stupid... */
  580.             STRPTR nw = infgetw(inpf);
  581.  
  582.             if (nw)
  583.             {
  584.                 BOOL err_rec = FALSE;   /* error var for recursive call */
  585.                 STRPTR endstr = NULL;
  586.  
  587.                 if (strcmp(nw, "("))
  588.                 {
  589.                     /* try to process another unary operator */
  590.                     inungetcw(inpf);
  591.                     eval_result = try_eval_unary_op(hp, dest, &err_rec);
  592.                 }
  593.                 else
  594.                     endstr = ")";
  595.  
  596.                 /* if not, process another expression */
  597.                 if (!eval_result && !err_rec)
  598.                     eval_result = eval_expression(hp, dest, endstr);
  599.             }
  600.             else
  601.                 hsc_msg_eof(hp, "after NOT");
  602.  
  603.             /* set result or return error */
  604.             if (eval_result)
  605.             {
  606.                 set_varbool(dest, !get_varbool(dest));
  607.                 eval_result = get_vartext(dest);
  608.             }
  609.             else
  610.                 *err = TRUE;
  611.         }
  612.         else if (!upstrcmp(nw, "DEFINED"))
  613.         {
  614.             nw = eval_attrname(hp);
  615.             if (nw)
  616.             {
  617.                 HSCATTR *attr = find_varname(hp->defattr, nw);
  618.  
  619.                 if (attr)
  620.                     set_varbool(dest, TRUE);
  621.                 else
  622.                     set_varbool(dest, FALSE);
  623.                 eval_result = get_vartext(dest);
  624.             }
  625.         }
  626.         else if (!upstrcmp(nw, "EXISTS"))
  627.         {
  628.             /* check existence of file (relative to destination dir) */
  629.             eval_result = eval_expression(hp, tmpdest, NULL);
  630.             if (eval_result)
  631.             {
  632.                 FILE *file = NULL;
  633.                 EXPSTR *dest_fname = init_estr(64);
  634.  
  635.                 D(fprintf(stderr, DHL "  EXISTS(`%s')\n", eval_result));
  636.  
  637.                 conv_hscuri2file(hp, dest_fname, eval_result);
  638.                 file = fopen(estr2str(dest_fname), "r");
  639.                 if (file)
  640.                 {
  641.                     fclose(file);
  642.                     set_varbool(dest, TRUE);
  643.                 }
  644.                 else
  645.                     set_varbool(dest, FALSE);
  646.  
  647.                 del_estr(dest_fname);
  648.                 eval_result = get_vartext(dest);
  649.             }
  650.         }
  651.         else if (!upstrcmp(nw, "FEXISTS"))
  652.         {
  653.             /* check existence of file */
  654.             eval_result = eval_expression(hp, tmpdest, NULL);
  655.             if (eval_result)
  656.             {
  657.                 FILE *file = NULL;
  658.                 EXPSTR *dest_fname = init_estr(64);
  659.  
  660.                 D(fprintf(stderr, DHL "  EXISTS(`%s')\n", eval_result));
  661.  
  662.                 file = fopen(eval_result, "r");
  663.                 if (file)
  664.                 {
  665.                     fclose(file);
  666.                     set_varbool(dest, TRUE);
  667.                 }
  668.                 else
  669.                     set_varbool(dest, FALSE);
  670.  
  671.                 del_estr(dest_fname);
  672.                 eval_result = get_vartext(dest);
  673.             }
  674.         }
  675.         else if (!upstrcmp(nw, "GETENV"))
  676.         {
  677.             /* get environment variable */
  678.             eval_result = eval_expression(hp, dest, NULL);
  679.             if (eval_result)
  680.             {
  681.                 STRPTR env_value = getenv(get_vartext(dest));
  682.  
  683.                 D(fprintf(stderr, DHL "  GETENV(`%s')\n", eval_result));
  684.                 if (!env_value)
  685.                 {
  686.                     hsc_message(hp, MSG_UNKN_ENVVAR,
  687.                                 "unknown environment variable %q",
  688.                                 get_vartext(dest));
  689.  
  690.                     env_value = "";
  691.                 }
  692.                 set_vartext(dest, env_value);
  693.                 eval_result = get_vartext(dest);
  694.                 D(fprintf(stderr, DHL "  =`%s'\n", eval_result));
  695.             }
  696.         }
  697.         else if (!upstrcmp(nw, "GETFILESIZE"))
  698.         {
  699.             /* retrieve size of a file */
  700.             EXPSTR *filesizestr = init_estr(0);
  701.             HSCATTR *filedestattr = new_hscattr(PREFIX_TMPATTR "get.filesize");
  702.             STRPTR filename = NULL;
  703.  
  704.             eval_result = NULL;
  705.             filedestattr->vartype = VT_STRING;
  706.             filename = eval_expression(hp, filedestattr, NULL);
  707.             if (filename)
  708.             {
  709.                 eval_result = getfilesize(hp, filesizestr, filename);
  710.             }
  711.             if (eval_result)
  712.             {
  713.                 set_vartext(dest, eval_result);
  714.                 eval_result = get_vartext(dest);
  715.             }
  716.             del_hscattr(filedestattr);
  717.             del_estr(filesizestr);
  718.         }
  719.         else if (!upstrcmp(nw, "GETTIME"))
  720.         {
  721.             /* get local time */
  722.             EXPSTR *timestr = gettimestr(hp, localtime(&(hp->start_time)));
  723.  
  724.             D(fprintf(stderr, DHL "  GETTIME\n"));
  725.             if (timestr)
  726.             {
  727.                 set_vartext(dest, estr2str(timestr));
  728.                 del_estr(timestr);
  729.                 eval_result = get_vartext(dest);
  730.             }
  731.             check_brakets(hp);
  732.         }
  733.         else if (!upstrcmp(nw, "GETGMTIME"))
  734.         {
  735.             /* get greenwich mean time */
  736.             EXPSTR *timestr = gettimestr(hp, gmtime(&(hp->start_time)));
  737.  
  738.             D(fprintf(stderr, DHL "  GETGMTIME\n"));
  739.             if (timestr)
  740.             {
  741.                 set_vartext(dest, estr2str(timestr));
  742.                 del_estr(timestr);
  743.                 eval_result = get_vartext(dest);
  744.             }
  745.             check_brakets(hp);
  746.         }
  747.         else if (!upstrcmp(nw, "SET"))
  748.         {
  749.  
  750.             nw = eval_attrname(hp);
  751.             if (nw)
  752.             {
  753.                 HSCATTR *attr = find_varname(hp->defattr, nw);
  754.  
  755.                 if (attr)
  756.                 {
  757.                     if (attr->vartype == VT_BOOL)
  758.                     {
  759.                         set_varbool(dest, get_varbool(attr));
  760.                     }
  761.                     else if (get_vartext(attr))
  762.                         set_varbool(dest, TRUE);
  763.                     else
  764.                         set_varbool(dest, FALSE);
  765.                     eval_result = get_vartext(dest);
  766.                 }
  767.                 else
  768.                 {
  769.                     hsc_msg_unkn_attr_ref(hp, nw);
  770.                     *err = TRUE;
  771.                 }
  772.             }
  773.         }
  774.         else
  775.             inungetcw(inpf);
  776.     }
  777.  
  778.     del_hscattr(tmpdest);
  779.  
  780.     if (!nw)
  781.         *err = TRUE;
  782.  
  783.     return (eval_result);
  784. }
  785.  
  786. /*
  787.  * eval_op
  788.  *
  789.  * evaluate binary operator string
  790.  */
  791. static BYTE eval_op(HSCPRC * hp)
  792. {
  793.     BYTE op = OP_NONE;
  794.     BOOL op_eof = FALSE;        /* flag: end of file reached */
  795.     INFILE *inpf = hp->inpf;
  796.     STRPTR nw = infgetw(inpf);
  797.  
  798.     D(fprintf(stderr, DHL "  operator \"%s", nw));
  799.  
  800.     if (nw)
  801.     {
  802.         /* boolean operators */
  803.         if (!upstrcmp(nw, OP_AND_STR))
  804.         {
  805.             op = OP_AND;
  806.         }
  807.         else if (!upstrcmp(nw, OP_OR_STR))
  808.         {
  809.             op = OP_OR;
  810.         }
  811.         else if (!upstrcmp(nw, OP_XOR_STR))
  812.         {
  813.             op = OP_XOR;
  814.         }
  815.         else if (!strcmp(nw, OP_CAT_STR))
  816.         {
  817.             /* concatenation operator */
  818.             op = OP_CAT;
  819.         }
  820.         else if (!strcmp(nw, OP_SUB_STR))
  821.         {
  822.             /* subtraction operator */
  823.             op = OP_SUB;
  824.         }
  825.         else if (!strcmp(nw, OP_MUL_STR))
  826.         {
  827.             /* multiplication operator */
  828.             op = OP_MUL;
  829.         }
  830.         else if (!strcmp(nw, OP_DIV_STR))
  831.         {
  832.             /* division operator */
  833.             op = OP_DIV;
  834.         }
  835.         else if (!strcmp(nw, OP_MOD_STR))
  836.         {
  837.             /* modulo operator */
  838.             op = OP_MOD;
  839.         }
  840.         else if (!strcmp(nw, OP_INSIDE_STR))
  841.         {
  842.             /* substring search */
  843.             op = OP_INSIDE;
  844.         }
  845.         /* closing braket */
  846.         else if (!strcmp(nw, OP_CL_BRAKET_STR))
  847.         {
  848.             op = OP_CL_BRAKET;
  849.         }
  850.         else if (strenum(nw, "<|=|>", '|', STEN_CASE))
  851.         {
  852.             /* comparison operators */
  853.             STRARR opstr[3];
  854.             int ch;
  855.  
  856.             /* determine whole comparison operator:
  857.              * take first word, and check for next
  858.              * single character, if it is one of
  859.              * "<", "=" or ">", too. if so, append
  860.              * it to the string that tells the
  861.              * operator.
  862.              */
  863.             strcpy(opstr, nw);
  864.             ch = infgetc(inpf);
  865.             if (ch != EOF)
  866.             {
  867.                 D(fprintf(stderr, "%c", (char) ch));
  868.  
  869.                 if (strchr("<=>", ch))
  870.                 {
  871.                     opstr[1] = ch;
  872.                     opstr[2] = 0;
  873.                 }
  874.                 else
  875.                     inungetc(ch, inpf);
  876.             }
  877.             else
  878.                 op_eof = TRUE;
  879.  
  880.             /* find out comparison operator */
  881.             if (!strcmp(nw, OP_EQ_STR))
  882.                 op = OP_EQ;
  883.             else if (!strcmp(nw, OP_NEQ_STR))
  884.                 op = OP_EQ;
  885.             else if (!strcmp(nw, OP_GT_STR))
  886.                 op = OP_GT;
  887.             else if (!strcmp(nw, OP_LT_STR))
  888.                 op = OP_LT;
  889.             else if (!strcmp(nw, OP_LTE_STR))
  890.                 op = OP_LTE;
  891.             else if (!strcmp(nw, OP_GTE_STR))
  892.                 op = OP_GTE;
  893.             else if (!strcmp(nw, OP_CEQ_STR))
  894.                 op = OP_CEQ;
  895.             else
  896.                 err_op(hp, opstr);
  897.         }
  898.         else
  899.         {
  900.             err_op(hp, nw);
  901.         }
  902.     }
  903.     else
  904.     {
  905.         op_eof = TRUE;
  906.     }
  907.  
  908.     D(fprintf(stderr, "\"\n"));
  909.  
  910.     if (op_eof)
  911.     {
  912.         hsc_msg_eof(hp, "operator expected");
  913.     }
  914.  
  915.     return (op);
  916. }
  917.  
  918. /*
  919.  * stroptol
  920.  *
  921.  * convert string operand to long int; treat "" as 0,
  922.  * any non-numeric values as 1
  923.  *
  924.  * this enables to use boolean vars in numeric expressions
  925.  *
  926.  * result: TRUE
  927.  */
  928. static BOOL stroptol(HSCPRC *hp, LONG *dest, STRPTR str)
  929. {
  930.     BOOL ok = TRUE;
  931.  
  932.     *dest = 0;
  933.  
  934.     if (str[0])
  935.     {
  936.         STRPTR last_char = NULL;
  937.         *dest = strtol(str, &last_char, 0);
  938.         if (!last_char || (last_char[0]))
  939.         {
  940.             *dest = 1;
  941.         }
  942.     }
  943.     else
  944.     {
  945.         /* empty string "" counts as 0, too */
  946.     }
  947.  
  948.     return ok;
  949. }
  950.  
  951. /*
  952.  * process_arithmetic_op
  953.  */
  954. static BOOL process_arithmetic_op(HSCPRC * hp, EXPSTR *result, BYTE op, STRPTR str1, STRPTR str2)
  955. {
  956.     BOOL result_set = TRUE;
  957.     LONG int1 = 0;              /* integer value of string operands */
  958.     LONG int2 = 0;
  959.     LONG intr = 0;              /* integer result */
  960.  
  961.     /* convert both string operands to integers */
  962.     result_set = stroptol(hp, &int1, str1);
  963.     result_set &= stroptol(hp, &int2, str2);
  964.  
  965.     switch (op)
  966.     {
  967.     case OP_CAT:
  968.         intr = int1 + int2;
  969.         break;
  970.     case OP_SUB:
  971.         intr = int1 - int2;
  972.         break;
  973.     case OP_MUL:
  974.         intr = int1 * int2;
  975.         break;
  976.     case OP_DIV:
  977.         intr = int1 / int2;
  978.         break;
  979.     case OP_MOD:
  980.         intr = int1 % int2;
  981.         break;
  982.     default:
  983.         panic("unknown arithmetic operator");
  984.         break;
  985.     }
  986.  
  987.     /* set result */
  988.     if (result_set)
  989.     {
  990.         STRARR buf[20];
  991.         sprintf(buf, "%ld", intr);
  992.         set_estr(result, buf);
  993.     }
  994.  
  995.     return result_set;
  996. }
  997.  
  998. static BOOL process_boolean_op(HSCPRC *hp, HSCATTR *dest, BYTE op, STRPTR str1, STRPTR str2)
  999. {
  1000.     BOOL bool_val1 = eval_boolstr(str1);
  1001.     BOOL bool_val2 = eval_boolstr(str2);
  1002.     BOOL bool_valr = FALSE;
  1003.  
  1004.     switch (op)
  1005.     {
  1006.     case OP_AND:
  1007.         if (bool_val1 && bool_val2)
  1008.         {
  1009.             bool_valr = TRUE;
  1010.         }
  1011.         break;
  1012.  
  1013.     case OP_OR:
  1014.         if (bool_val1 || bool_val2)
  1015.         {
  1016.             bool_valr = TRUE;
  1017.         }
  1018.         break;
  1019.  
  1020.     case OP_XOR:
  1021.         if ((bool_val1 || bool_val2)
  1022.             && !(bool_val1 && bool_val2)
  1023.             )
  1024.         {
  1025.             bool_valr = TRUE;
  1026.         }
  1027.         break;
  1028.     default:
  1029.         panic("unknown boolean operator");
  1030.         break;
  1031.     }
  1032.  
  1033.     set_varbool(dest, bool_valr);
  1034.  
  1035.     return FALSE;
  1036. }
  1037.  
  1038. /*
  1039.  * process_op
  1040.  */
  1041. static VOID process_op(HSCPRC * hp, HSCATTR * dest, BYTE op, STRPTR str1, STRPTR str2)
  1042. {
  1043.     EXPSTR *result = init_estr(40);
  1044.     BOOL result_set = FALSE;
  1045.  
  1046.     D(fprintf(stderr, DHL "  \"%s\", \"%s\"\n", str1, str2));
  1047.     if (str2 && (op != OP_NONE))
  1048.     {
  1049.         switch (op)
  1050.         {
  1051.         case OP_CAT:
  1052.  
  1053.             if (dest->vartype != VT_NUM)
  1054.             {
  1055.                 /* concat two expressions */
  1056.                 set_estr(result, str1);
  1057.                 app_estr(result, str2);
  1058.                 result_set = TRUE;
  1059.             }
  1060.             else
  1061.             {
  1062.                 result_set = process_arithmetic_op(hp, result, op, str1, str2);
  1063.             }
  1064.  
  1065.             break;
  1066.  
  1067.         case OP_INSIDE:
  1068.  
  1069.             /* sub-string search, ignore case */
  1070.             if (upstrstr(str2, str1))
  1071.             {
  1072.                 set_varbool(dest, TRUE);
  1073.             }
  1074.             else
  1075.             {
  1076.                 set_varbool(dest, FALSE);
  1077.             }
  1078.             break;
  1079.  
  1080.         case OP_AND:
  1081.         case OP_OR:
  1082.         case OP_XOR:
  1083.             result_set = process_boolean_op(hp, dest, op, str1, str2);
  1084.             break;
  1085.  
  1086.         case OP_SUB:
  1087.         case OP_MUL:
  1088.         case OP_DIV:
  1089.         case OP_MOD:
  1090.             result_set = process_arithmetic_op(hp, result, op, str1, str2);
  1091.             break;
  1092.  
  1093.         case OP_EQ:
  1094.  
  1095.             /* string comparison, ignore case */
  1096.             if (!upstrcmp(str1, str2))
  1097.             {
  1098.                 set_varbool(dest, TRUE);
  1099.             }
  1100.             else
  1101.             {
  1102.                 set_varbool(dest, FALSE);
  1103.             }
  1104.             break;
  1105.  
  1106.         case OP_NEQ:
  1107.  
  1108.             /* string comparison "<>" */
  1109.             if (upstrcmp(str1, str2))
  1110.             {
  1111.                 set_varbool(dest, TRUE);
  1112.             }
  1113.             else
  1114.             {
  1115.                 set_varbool(dest, FALSE);
  1116.             }
  1117.             break;
  1118.  
  1119.         case OP_GT:
  1120.  
  1121.             /* string comparison ">" */
  1122.             if (upstrcmp(str1, str2) > 0)
  1123.             {
  1124.                 set_varbool(dest, TRUE);
  1125.             }
  1126.             else
  1127.             {
  1128.                 set_varbool(dest, FALSE);
  1129.             }
  1130.             break;
  1131.  
  1132.         case OP_LT:
  1133.  
  1134.             /* string comparison "<" */
  1135.             if (upstrcmp(str1, str2) < 0)
  1136.             {
  1137.                 set_varbool(dest, TRUE);
  1138.             }
  1139.             else
  1140.             {
  1141.                 set_varbool(dest, FALSE);
  1142.             }
  1143.             break;
  1144.  
  1145.         case OP_GTE:
  1146.  
  1147.             /* string comparison ">=" */
  1148.             if (upstrcmp(str1, str2) >= 0)
  1149.             {
  1150.                 set_varbool(dest, TRUE);
  1151.             }
  1152.             else
  1153.             {
  1154.                 set_varbool(dest, FALSE);
  1155.             }
  1156.             break;
  1157.  
  1158.         case OP_LTE:
  1159.  
  1160.             /* string comparison "<=" */
  1161.             if (upstrcmp(str1, str2) <= 0)
  1162.             {
  1163.                 set_varbool(dest, TRUE);
  1164.             }
  1165.             else
  1166.             {
  1167.                 set_varbool(dest, FALSE);
  1168.             }
  1169.             break;
  1170.  
  1171.         case OP_CEQ:
  1172.  
  1173.             /* string comparison, case sensitive */
  1174.             if (!strcmp(str1, str2))
  1175.             {
  1176.                 set_varbool(dest, TRUE);
  1177.             }
  1178.             else
  1179.             {
  1180.                 set_varbool(dest, FALSE);
  1181.             }
  1182.             break;
  1183.         default:
  1184.             panic("empty operator");
  1185.             break;
  1186.         }
  1187.     }
  1188.     /* store result in destination attribute,
  1189.      * if this has not happened yet
  1190.      */
  1191.     if (result_set)
  1192.     {
  1193.         set_vartext(dest, estr2str(result));
  1194.     }
  1195.  
  1196.     /* remove temp. string for result */
  1197.     del_estr(result);
  1198. }
  1199.  
  1200. /*
  1201.  *-------------------------------------
  1202.  * eval_expression: evaluate expression
  1203.  *-------------------------------------
  1204.  */
  1205.  
  1206. /*
  1207.  * eval_string_expr
  1208.  *
  1209.  * evaluate string expression WITH enclosing quotes
  1210.  */
  1211. static STRPTR eval_string_expr(HSCPRC * hp, HSCATTR * dest)
  1212. {
  1213.     INFILE *inpf = hp->inpf;
  1214.     STRPTR eval_result = NULL;
  1215.     EXPSTR *tmpstr = init_estr(TMP_STEPSIZE);
  1216.     int quote;
  1217.  
  1218.     /* get quote char */
  1219.     quote = infgetc(inpf);
  1220.     if (quote != EOF)
  1221.     {
  1222.         BOOL end = FALSE;
  1223.  
  1224.         while (!end)
  1225.         {
  1226.             int ch = infgetc(inpf);
  1227.             if (ch == EOF)
  1228.             {
  1229.                 hsc_msg_eof(hp, "reading string constant");
  1230.                 eval_result = NULL;
  1231.                 end = TRUE;
  1232.             }
  1233.             else if (ch != quote)
  1234.             {
  1235.                 /* check for LF inside string */
  1236.                 if (ch == '\n')
  1237.                     hsc_message(hp, MSG_STR_LF,
  1238.                                 "linefeed found inside string");
  1239.  
  1240.                 /* append next char to string */
  1241.                 app_estrch(tmpstr, ch);
  1242.             }
  1243.             else
  1244.             {
  1245.                 /* closing quote reached */
  1246.                 eval_result = estr2str(tmpstr);
  1247.                 end = TRUE;
  1248.             }
  1249.         }
  1250.     }
  1251.     else
  1252.         hsc_msg_eof(hp, "reading string constant");
  1253.  
  1254.     /* set new attribute value */
  1255.     if (eval_result)
  1256.     {
  1257.         /* set new quotes */
  1258.         dest->quote = quote;
  1259.         /* set new value */
  1260.         set_vartext(dest, eval_result);
  1261.         eval_result = get_vartext(dest);
  1262.     }
  1263.     /* remove temp. string */
  1264.     del_estr(tmpstr);
  1265.  
  1266.     return (eval_result);
  1267. }
  1268.  
  1269. /*
  1270.  * eval_string_expr_noquote
  1271.  *
  1272.  * evaluate string expression WITHOUT enclosing quotes
  1273.  */
  1274. STRPTR eval_string_expr_noquote(HSCPRC * hp, HSCATTR * dest)
  1275. {
  1276.     /* TODO: check for ch==">": attrval missing */
  1277.     INFILE *inpf = hp->inpf;
  1278.     STRPTR eval_result = NULL;
  1279.     EXPSTR *tmpstr = init_estr(TMP_STEPSIZE);
  1280.     BOOL end = FALSE;
  1281.  
  1282.     /* TODO: check for empty expression */
  1283.  
  1284.     /*
  1285.      * read next char from input file until a
  1286.      * closing quote if found.
  1287.      * if the arg had no quote, a white space
  1288.      * or a '>' is used to detect end of arg.
  1289.      * if a LF is found, view error message
  1290.      */
  1291.     while (!end)
  1292.     {
  1293.  
  1294.         int ch = infgetc(inpf);
  1295.         if (ch == EOF)
  1296.         {
  1297.             hsc_msg_eof(hp, "reading attribute");
  1298.  
  1299.             end = TRUE;
  1300.         }
  1301.         else if ((ch == '\n')
  1302.                  || (inf_isws(ch, inpf) || (ch == '>')))
  1303.         {
  1304.             /* end of arg reached */
  1305.             inungetc(ch, inpf);
  1306.             eval_result = estr2str(tmpstr);
  1307.             end = TRUE;
  1308.         }
  1309.         else
  1310.         {
  1311.             /* append next char to tmpstr */
  1312.             app_estrch(tmpstr, ch);
  1313.         }
  1314.     }
  1315.  
  1316.     /* set new attribute value */
  1317.     if (eval_result)
  1318.     {
  1319.         set_vartext(dest, eval_result);
  1320.         eval_result = get_vartext(dest);
  1321.     }
  1322.     /* remove temp. string */
  1323.     del_estr(tmpstr);
  1324.  
  1325.     return (eval_result);
  1326. }
  1327.  
  1328. /*
  1329.  * eval_attrref
  1330.  *
  1331.  * evaluate reference to attribute
  1332.  *
  1333.  */
  1334. static STRPTR eval_attrref(HSCPRC * hp, HSCATTR * destattr)
  1335. {
  1336.     STRPTR eval_result = NULL;
  1337.     STRPTR nw = eval_attrname(hp);
  1338.  
  1339.     if (nw)
  1340.     {
  1341.         HSCATTR *refvar = find_varname(hp->defattr, nw);
  1342.  
  1343.         if (refvar)
  1344.         {
  1345.             /* TODO: type checking */
  1346.             destattr->quote = refvar->quote;
  1347.             eval_result = refvar->text;
  1348.  
  1349.             /* check empty/circular reference */
  1350.             if (!eval_result)
  1351.                 hsc_message(hp, MSG_EMPTY_SYMB_REF,
  1352.                             "empty reference to %A", destattr);
  1353.  
  1354.             /* debugging message */
  1355.             DDA(fprintf(stderr, DHL "   %s refers to (%s)\n",
  1356.                         destattr->name, refvar->name));
  1357.         }
  1358.         else
  1359.         {
  1360.             /* reference to unknown destattr */
  1361.             hsc_msg_unkn_attr_ref(hp, nw);
  1362.         }
  1363.  
  1364.         /* set empty value for reference to NULL */
  1365.         if ((!refvar) || (!eval_result))
  1366.         {
  1367.             /* return empty destattr */
  1368.             destattr->quote = '"';
  1369.             eval_result = "";
  1370.         }
  1371.     }
  1372.  
  1373.     /* set value of destination attribute */
  1374.     if (eval_result)
  1375.         set_vartext(destattr, eval_result);
  1376.  
  1377.     return (eval_result);
  1378. }
  1379.  
  1380. /*
  1381.  * eval_expression
  1382.  *
  1383.  * params: dest....attribute where to store result in
  1384.  *         inpf....input file
  1385.  *         err.....flag that is set to TRUE if an error occured
  1386.  *         endstr..word that is expected at end of expession;
  1387.  *                 NULL for no special ending word
  1388.  * result: result of evaluation (IF_TRUE or FALSE)
  1389.  *
  1390.  * NOTE: if endstr==NULL, that means that eval_expression() is called
  1391.  *   immediatly after the "=" of an attribute. In this case, if no
  1392.  *   quotes are found as next char, all chars are read until the next
  1393.  *   white-space or LF occures.
  1394.  *   If no special char was found until now (only "A".."Z", "_", "-" and
  1395.  *   digits occured), we first interpret the string as name for an
  1396.  *   attribute reference; if such an attribute does not exist, it is
  1397.  *   asumed that the value passed is a string constant (same as it would
  1398.  *   have been enclosed in quotes).
  1399.  *
  1400.  */
  1401. STRPTR eval_expression(HSCPRC * hp, HSCATTR * dest, STRPTR endstr)
  1402. {
  1403.     /* TODO: endstr needs to be boolean flag only */
  1404.     INFILE *inpf = hp->inpf;
  1405.     EXPSTR *vararg = init_estr(TMP_STEPSIZE);
  1406.     /* used as destination by eval_string_exprXX() */
  1407.  
  1408.     STRPTR exprstr = NULL;      /* return value */
  1409.     int ch;                     /* char read from input */
  1410.  
  1411.     /* skip white spaces */
  1412.     infskip_ws(inpf);
  1413.  
  1414.     /* read dest->quote char */
  1415.     ch = infgetc(inpf);
  1416.     if (!strchr(VQ_STR_QUOTE, ch))
  1417.         if (ch != EOF)
  1418.             dest->quote = VQ_NO_QUOTE;
  1419.         else
  1420.             hsc_msg_eof(hp, "reading attribute");
  1421.     else
  1422.         dest->quote = ch;
  1423.  
  1424.     if (ch == '(')
  1425.     {
  1426.         /* process braket */
  1427.         exprstr = eval_expression(hp, dest, ")");
  1428.  
  1429.         /* set generic double quote */
  1430.         if (!endstr)
  1431.             dest->quote = '\"';
  1432.     }
  1433.     else if (ch != EOF)
  1434.     {
  1435.         /* write current char read back to input buffer */
  1436.         inungetc(ch, inpf);
  1437.  
  1438.         if (dest->quote != VQ_NO_QUOTE)
  1439.         {
  1440.             /* process string expression with quotes */
  1441.             exprstr = eval_string_expr(hp, dest);
  1442.         }
  1443.         else if (endstr)
  1444.         {
  1445.             BOOL err = FALSE;
  1446.  
  1447.             /* try to process unary operator */
  1448.             exprstr = try_eval_unary_op(hp, dest, &err);
  1449.  
  1450.             /* process attribute reference */
  1451.             if (!exprstr && !err)
  1452.                 exprstr = eval_attrref(hp, dest);
  1453.         }
  1454.         else
  1455.         {
  1456.             /* process string expression without quotes */
  1457.             exprstr = eval_string_expr_noquote(hp, dest);
  1458.         }
  1459.     }
  1460.  
  1461.     if (exprstr && endstr)
  1462.     {
  1463.         BYTE op;
  1464.  
  1465.         /* evaluate operator */
  1466.         op = eval_op(hp);
  1467.  
  1468.         if (op == OP_CL_BRAKET)
  1469.         {
  1470.             DMSG("  END mark operator reached");
  1471.         }
  1472.         else if (op != OP_NONE)
  1473.         {
  1474.             /* no endmark reached */
  1475.             STRPTR str1 = exprstr;
  1476.  
  1477.             /* read second operator */
  1478.             if (op != OP_NONE)
  1479.             {
  1480.                 STRPTR str2 = NULL;
  1481.                 HSCATTR *dest1 = new_hscattr(PREFIX_TMPATTR "2nd.operand");
  1482.  
  1483.                 /* init dummy attribute */
  1484.                 dest1->vartype = dest->vartype;
  1485.                 dest1->quote = dest->quote;
  1486.  
  1487.                 /* compute second value */
  1488.                 str2 = eval_expression(hp, dest1, endstr);
  1489.  
  1490.                 if (str2)
  1491.                 {
  1492.                     process_op(hp, dest, op, str1, str2);
  1493.                 }
  1494.                 else
  1495.                 {
  1496.                     exprstr = NULL;
  1497.                 }
  1498.  
  1499.                 /* remove result of second value */
  1500.                 del_hscattr((APTR) dest1);
  1501.             }
  1502.             else
  1503.             {
  1504.                 /* TODO: skip expression until ">" */
  1505.                 exprstr = NULL;
  1506.             }
  1507.  
  1508.             if (exprstr)
  1509.             {
  1510.                 /* store result */
  1511.                 exprstr = get_vartext(dest);
  1512.             }
  1513.         }
  1514.         else
  1515.         {
  1516.             DMSG("  NO operator");
  1517.         }
  1518.     }
  1519.  
  1520.     if (!endstr)
  1521.     {
  1522.         if (exprstr && !endstr)
  1523.         {
  1524.             if ((dest->vartype != VT_BOOL)
  1525.                 && !(dest->varflag & (VF_MACRO | VF_KEEP_QUOTES)))
  1526.             {
  1527.                 choose_quote(hp, dest);
  1528.             }
  1529.  
  1530.             /*
  1531.              * check enum type
  1532.              */
  1533.             if (dest->vartype == VT_ENUM)
  1534.             {
  1535.                 if (!strenum(exprstr, dest->enumstr, '|', STEN_NOCASE))
  1536.                 {
  1537.                     /* unknown enum value */
  1538.                     hsc_message(hp, MSG_ENUM_UNKN,
  1539.                                 "unknown value %q for enumerator %A",
  1540.                                 exprstr, dest);
  1541.                 }
  1542.             }
  1543.             /*
  1544.              * check color value
  1545.              */
  1546.             else if (dest->vartype == VT_COLOR)
  1547.             {
  1548.                 BOOL ok = FALSE;
  1549.                 size_t color_len = strlen("#rrggbb");
  1550.  
  1551.                 if (exprstr[0] == '#')
  1552.                 {
  1553.                     /* check RGB-value */
  1554.                     if (strlen(exprstr) == color_len)
  1555.                     {
  1556.                         size_t i = 1;
  1557.  
  1558.                         ok = TRUE;
  1559.                         for (; i < color_len; i++)
  1560.                             if (!isxdigit(exprstr[i]))
  1561.                                 ok = FALSE;
  1562.                     }
  1563.                 }
  1564.                 else
  1565.                 {
  1566.                     /* check color name */
  1567.                     if (hp->color_names)
  1568.                     {
  1569.                         if (strenum(exprstr, hp->color_names, '|', STEN_NOCASE))
  1570.                             ok = TRUE;
  1571.                     }
  1572.                     else
  1573.                         ok = TRUE;
  1574.                 }
  1575.  
  1576.                 if (!ok)
  1577.                     /* illegal color value */
  1578.                     hsc_message(hp, MSG_ILLG_COLOR,
  1579.                                 "illegal color value %q for %A",
  1580.                                 exprstr, dest);
  1581.             }
  1582.             /*
  1583.              * check numeric value
  1584.              */
  1585.             else if (dest->vartype == VT_NUM)
  1586.             {
  1587.                 BOOL ok = FALSE;
  1588.                 int i = 0;
  1589.  
  1590.                 if ((exprstr[0] == '+')
  1591.                     || (exprstr[0] == '-'))
  1592.                 {
  1593.                     i = 1;
  1594.                 }
  1595.                 if (strlen(exprstr) - i)
  1596.                 {
  1597.                     ok = TRUE;
  1598.                     while (exprstr[i] && ok)
  1599.                     {
  1600.                         if (!isdigit(exprstr[i]))
  1601.                             ok = FALSE;
  1602.                         else
  1603.                             i++;
  1604.                     }
  1605.                 }
  1606.                 if (!ok)
  1607.                 {
  1608.                     /* unknown enum value */
  1609.                     hsc_message(hp, MSG_ILLG_NUM,
  1610.                                 "illegal numeric value %q for %A",
  1611.                                 exprstr, dest);
  1612.                 }
  1613.             }
  1614.             /*
  1615.              * for boolean attributes, set the name
  1616.              * of the attribute if TRUE, or set an
  1617.              * empty string, if FALSE
  1618.              */
  1619.             else if (dest->vartype == VT_BOOL)
  1620.             {
  1621.                 if (eval_boolstr(exprstr))
  1622.                 {
  1623.                     set_vartext(dest, dest->name);
  1624.                 }
  1625.                 else
  1626.                 {
  1627.                     set_vartext(dest, "");
  1628.                 }
  1629.             }
  1630.  
  1631.             /*
  1632.              * checks performed only for tags,
  1633.              * but are skipped for macros
  1634.              */
  1635.             if (!(dest->varflag & VF_MACRO))
  1636.             {
  1637.                 /*
  1638.                  * parse uri (convert abs.uris, check existence)
  1639.                  */
  1640.                 if (dest->vartype == VT_URI)
  1641.                 {
  1642.                     EXPSTR *dest_uri = init_estr(32);
  1643.  
  1644.                     parse_uri(hp, dest_uri, exprstr);
  1645.                     set_vartext(dest, estr2str(dest_uri));
  1646.  
  1647.                     del_estr(dest_uri);
  1648.                 }
  1649.             }
  1650.             exprstr = get_vartext(dest);
  1651.         }
  1652.         else
  1653.         {
  1654.             /* if error occured,
  1655.              * skip until ">", unread ">"
  1656.              */
  1657.             skip_until_eot(hp, NULL);
  1658.             if (!hp->fatal)
  1659.             {
  1660.                 inungetcw(inpf);
  1661.             }
  1662.         }
  1663.     }
  1664.  
  1665.     del_estr(vararg);
  1666.  
  1667.     return (exprstr);
  1668. }
  1669.  
  1670. /*
  1671.  * assign_conditional_attr
  1672.  *
  1673.  * validate and find name of source attrib, if set, copy value
  1674.  * to destination attribute
  1675.  *
  1676.  * params: hp...........hsc-process
  1677.  *         dest.........detination attribute where to store value
  1678.  *         source_attr..name of source attribute
  1679.  * result: value of attribute, if it has been set, or NULL
  1680.  *         if attribute is empty or unknown or other error
  1681.  *         has occured.
  1682.  */
  1683. static STRPTR assign_conditional_attr(HSCPRC * hp, HSCATTR * dest, STRPTR source_name)
  1684. {
  1685.     STRPTR attrval = NULL;
  1686.  
  1687.     if (source_name)
  1688.     {
  1689.         if (check_attrname(hp, source_name))
  1690.         {
  1691.             HSCATTR *attr = find_varname(hp->defattr, source_name);
  1692.  
  1693.             if (attr)
  1694.             {
  1695.                 attrval = get_vartext(attr);
  1696.                 dest->quote = attr->quote;
  1697.             }
  1698.             else
  1699.             {
  1700.                 hsc_msg_unkn_attr_ref(hp, source_name);
  1701.             }
  1702.         }
  1703.     }
  1704.     else
  1705.     {
  1706.         panic("no source attribute");
  1707.     }
  1708.  
  1709.     /* update attribute value and quotes */
  1710.     if (attrval)
  1711.     {
  1712.         set_vartext(dest, attrval);
  1713.         attrval = get_vartext(dest);
  1714.         choose_quote(hp, dest);
  1715.     }
  1716.  
  1717.     return (attrval);
  1718. }
  1719.  
  1720. /*
  1721.  * eval_conditional_expression
  1722.  *
  1723.  * evaluate a conditional expression like
  1724.  *   SEPP?=HUGO or SEPP?=("hu"+"go")
  1725.  * and modify destination attribute only if the source
  1726.  * attribute really exists
  1727.  *
  1728.  * params: hp...hsc-process
  1729.  *         dest..target attribute to update
  1730.  * result: new value or NULL in case of no update or error
  1731.  */
  1732. STRPTR eval_conditional_assignment(HSCPRC * hp, HSCATTR * dest)
  1733. {
  1734.     STRPTR nw = infgetw(hp->inpf);
  1735.     STRPTR attr_val = NULL;
  1736.  
  1737.     D(fprintf(stderr, DHL "  conditional assignment\n"));
  1738.  
  1739.     if (nw)
  1740.     {
  1741.         /* temp. attribute to store name of source attribute if it
  1742.          * is specified with an expression */
  1743.         HSCATTR *tmp_attr = NULL;
  1744.         STRPTR source_name = NULL;      /* name of source attribute */
  1745.  
  1746.         if (!strcmp(nw, "("))
  1747.         {
  1748.             /* get attribute name from expression */
  1749.             tmp_attr = new_hscattr(PREFIX_TMPATTR "conditional.assignment");
  1750.             source_name = eval_expression(hp, tmp_attr, ")");
  1751.         }
  1752.         else
  1753.         {
  1754.             /* attribute name was simply specified */
  1755.             source_name = nw;
  1756.         }
  1757.  
  1758.         if (source_name)
  1759.         {
  1760.             D(fprintf(stderr, DHL "    assign from %s\n", source_name));
  1761.             attr_val = assign_conditional_attr(hp, dest, source_name);
  1762.         }
  1763.  
  1764.         /* free resources */
  1765.         if (tmp_attr)
  1766.         {
  1767.             del_hscattr(tmp_attr);
  1768.         }
  1769.  
  1770.     }
  1771.     else
  1772.     {
  1773.         hsc_msg_eof(hp, "conditional attribute identifier expected");
  1774.     }
  1775.  
  1776.     return (attr_val);
  1777. }
  1778.